/*
 * @Author: Wangjun
 * @Date: 2023-08-15 17:50:54
 * @LastEditTime: 2023-11-27 17:50:23
 * @LastEditors: Wangjun
 * @Description:
 * @FilePath: \xr_node_calcd:\go\src\gitee.com\hnxr_1\nodex\node.go
 * hnxr
 */
package nodex

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"gitee.com/hnxr_1/nodex/nodeconv"
)

var (
	mapNode = map[string]Noder{}
)

type Noder interface {
	Clone() Noder
	Init(mem *Memory) (err error)
	Calc() (err error)
	GetName() string
	GetID() string
	SetID(string)
	GetSN() int
	SetSN(int)
	GetParam(name string) (Valuer, error)
	GetParams() []Valuer
	SetEnQ(en bool)
	RegData() []byte //注册信息
	Outs() []*Out    //DO 需要使用
	GetModelID() int
	GetResult() (v float64, isBad bool) //获取最后的结果

	ResetValue() //初始化时使用

	//GetNode() *Node
	GetExtends() map[string]any
	SetExtends(ptr map[string]any)

	GetParent() *Parent
	SetParent(*Parent)
	GetMemory() *Memory //获取内存信息
	SetSon(o Noder)
	MakeUID() string
}

/**
 * @description: 注册算子
 * @param {Noder} n
 * @return {*}
 */
func Reister(n Noder) {
	node := mapNode[n.GetName()]
	if node != nil {
		panic(fmt.Sprintf("%s 算子已经注册过", n.GetName()))
	}
	mapNode[n.GetName()] = n
}

/**
 * @description: 复制且初始化计算节点
 * @param {string} name
 * @param {string} id
 * @return {*}
 */
func New(name string, id string) (node Noder) {
	temp := GetNode(name)
	if temp == nil {
		return
	}
	v := reflect.ValueOf(temp)
	v = reflect.Indirect(v)
	v = reflect.New(v.Type())
	obj := v.Interface()
	node = obj.(Noder)
	node.SetID(id)
	node.SetSon(node)

	return node
}

/**
 * @description: 获取指定的算子
 * @param {string} name
 * @return {*}
 */
func GetNode(name string) Noder {
	return mapNode[name]
}

/**
 * @description: 获取计算列表
 * @return {*}
 */
func GetNodeList() []Noder {
	nodes := make([]Noder, len(mapNode))
	i := 0
	for _, node := range mapNode {
		nodes[i] = node
		i++
	}
	return nodes
}

func RegData() []byte {
	buf := bytes.NewBufferString("[")
	nodes := GetNodeList()
	for i, node := range nodes {
		data := node.RegData()
		if i != 0 {
			buf.WriteByte(',')
		}
		buf.Write(data)
	}
	buf.WriteByte(']')
	return buf.Bytes()
}

type Port struct {
	DataType string `json:"dataType"`
	Desc     string `json:"desc"`
	Kind     string `json:"kind"`
	Name     string `json:"name"`
}

type Out struct {
	Name  string
	Value Outter
}

// 父节点数据
type Parent struct {
	RID      int //关联ID
	CRC      string
	Parent   string // 父节点，表示是一个打包的画布
	FileName string
	Category string //关联类别
	ExecTime int64
	Data     any
}

/**
 * @description: 生成唯一关键字
 * @return {*}
 */
func (m *Parent) MakeKey() string {
	fileName := strings.TrimSuffix(m.FileName, ".json")
	return fmt.Sprintf("%s-%s-%d", fileName, m.Category, m.RID)
}

type Memory struct {
	UID string //缓存的唯一key
	Ptr any    //存放的数据
}

type Node struct {
	son  Noder  //子类
	sn   int    //执行顺序
	outs []*Out //快捷输出
	//modelID int            //型号
	extends map[string]any //存放未知的数据
	ID      string         //算子ID
	Name    string         //算子名称
	Err     error          //错误
	Bad     bool           //质量是否有问题? false 质量好 true 质量有问题
	EnQ     bool           //true 启动质量位检查 false 不启用质量检查，当启用质量位检查后，如果质量有问题则不计算
	Parent  *Parent        `json:"-"` //关联父属性
	Memory  `json:"-"`
}

func GetNumber[T int64 | float64](a any) T {
	switch v := a.(type) {
	case bool:
		if v {
			return 1
		}
		return 0
	case *bool:
		if *v {
			return 1
		}
		return 0
	case int8:
		return T(v)
	case byte:
		return T(v)
	case int:
		return T(v)
	case int16:
		return T(v)
	case int32:
		return T(v)
	case int64:
		return T(v)
	case *int:
		return T(*v)
	case *int16:
		return T(*v)
	case *int32:
		return T(*v)
	case *int64:
		return T(*v)
	case uint:
		return T(v)
	case uint16:
		return T(v)
	case uint32:
		return T(v)
	case uint64:
		return T(v)
	case *uint:
		return T(*v)
	case *uint16:
		return T(*v)
	case *uint32:
		return T(*v)
	case *uint64:
		return T(*v)
	case float32:
		return T(v)
	case float64:
		return T(v)
	case *float32:
		return T(*v)
	case *float64:
		return T(*v)
	}
	return 0
}

func (m *Node) MakeUID() string {
	if m.Parent == nil {
		return m.ID
	}
	return fmt.Sprintf("%s-%s", m.Parent.MakeKey(), m.ID)
}

func (m *Node) GetMemory() *Memory {
	return &m.Memory
}

// 只在输出时有用
func (m *Node) GetResult() (v float64, isBad bool) {
	return
}

func (m *Node) GetParent() *Parent {
	return m.Parent
}

func (m *Node) SetParent(parent *Parent) {
	m.Parent = parent
}

/**
 * @description: 数据初始化
 * @return {*}
 */
func (m *Node) Init(mem *Memory) (err error) {
	return
}

func (m *Node) GetExtends() map[string]any {
	return m.extends
}

func (m *Node) SetExtends(ptr map[string]any) {
	m.extends = ptr
}

func (m *Node) Clone() (node Noder) {
	var ok bool
	v := reflect.ValueOf(m.son)
	v = reflect.Indirect(v)
	o := reflect.New(v.Type())
	obj := o.Interface()
	node, ok = obj.(Noder)
	if !ok {
		node = obj.(Noder) //方便在此加入断点
	}

	//node 对象赋值
	o = reflect.Indirect(o)
	n := o.FieldByName("Node")
	nd := n.Addr().Interface()
	nod := nd.(*Node)
	*nod = *m
	//设置子算子
	node.SetSon(node)
	//node.ResetValue()
	//参数属性复制

	oldParams := m.GetParams()
	newParams := node.GetParams()
	for i := range oldParams {
		newParams[i].CopyAttr(oldParams[i])
	}
	return
}

func (m *Node) GetID() string {
	return m.ID
}

/**
 * @description: 设置ID
 * @param {string} id
 * @return {*}
 */
func (m *Node) SetID(id string) {
	m.ID = id
}

/**
 * @description: 获取执行
 * @return {*}
 */
func (m *Node) GetSN() int {
	return m.sn
}

func (m *Node) SetSN(sn int) {
	m.sn = sn
}

func (m *Node) SetEnQ(en bool) {
	m.EnQ = en
}

func (m *Node) Outs() []*Out {
	return m.outs
}

func (m *Node) SetOuts(outs []*Out) {
	m.outs = outs
}

/**
 * @description: 默认支持的参数，如果要实现自定义参数，可以重写此方法
 * @param {string} name
 * @return {*}
 */
func (m *Node) GetParam(name string) (b Valuer, err error) {
	return GetParam(m.son, name)
}

/**
 * @description: 获取参数列表
 * @return {*}
 */
func (m *Node) GetParams() []Valuer {
	return GetParams(m.son)
}

/**
 * @description: 获取计算错误信息
 * @return {*}
 */
func (m *Node) Error() error {
	return m.Err
}

func (m *Node) SetSon(o Noder) {
	m.son = o
	m.Name = o.GetName()
	o.ResetValue()
}

func (m *Node) ResetValue() {
	v := reflect.ValueOf(m.son)
	v = reflect.Indirect(v)
	t := v.Type()
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		remark := f.Tag.Get("remark")
		isOut := false
		ss := strings.Split(remark, ",")
		if len(ss) > 2 {
			if ss[2] == "out" {
				isOut = true
			}
		}
		vv := v.Field(i)
		switch f.Type.Name() {
		case "Boolean":
			b := vv.Addr().Interface().(*Boolean)
			b.BoolValue = NewBoolValue()
			if isOut {
				b.Bad = &m.Bad
			}
		case "Double":
			b := vv.Addr().Interface().(*Double)
			b.DoubleValue = NewDoubleValue()
			if isOut {
				b.Bad = &m.Bad
			}
		case "ArrayDouble":
			b := vv.Addr().Interface().(*ArrayDouble)
			b.ArrayDoubleValue = NewArrayDoubleValue()
			if isOut {
				b.Bad = &m.Bad
			}
		case "ArrayBool":
			b := vv.Addr().Interface().(*ArrayBool)
			b.ArrayBoolValue = NewArrayBoolValue()
			if isOut {
				b.Bad = &m.Bad
			}
		}
	}
}

/**
 * @description: 自动获取需要的参数
 * @param {any} o
 * @param {string} name
 * @return {*}
 */
func GetParam(o Noder, name string) (b Valuer, err error) {
	v := reflect.ValueOf(o)
	v = reflect.Indirect(v)
	t := v.Type()
	sf, ok := t.FieldByName(name)
	if !ok {
		err = errors.New(o.GetName() + ":无效的参数:" + name)
		return
	}
	if !IsParam(sf.Type.Name()) {
		err = errors.New(o.GetName() + ":无效的参数:" + name)
		return
	}
	v = v.FieldByName(name)
	a := v.Addr().Interface()
	b = a.(Valuer)
	return
}

func GetParams(o Noder) []Valuer {
	var vals []Valuer

	v := reflect.ValueOf(o)
	v = reflect.Indirect(v)
	t := v.Type()
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		if IsParam(f.Type.Name()) {
			vv := v.Field(i)
			val := vv.Addr().Interface().(Valuer)
			vals = append(vals, val)
		}
	}
	return vals
	//return []nodex.Valuer{&m.X1, &m.Y}
}

/**
 * @description: 生成注册数据
 * @param {any} o
 * @param {*} name
 * @param {*} sysmbol
 * @param {string} desc
 * @param {int} modelID
 * @return {*}
 */
func MakeRegData(o Noder, name, sysmbol, desc string) (bs []byte) {
	v := reflect.ValueOf(o)
	v = reflect.Indirect(v)
	t := v.Type()
	var ins []*nodeconv.Param
	var outs []*nodeconv.Param
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		remark := f.Tag.Get("remark")
		if !IsParam(f.Type.Name()) {
			continue
		}
		//tag: 说明 第一列 描述,第二列默认值, 第三列是否是输出
		var param *nodeconv.Param
		ss := strings.Split(remark, ",")
		param = nodeconv.NewParam(f.Name, f.Type.Name(), ss[0])
		param.DefaultValue = GetParamDefaultValue(f.Type.Name())
		if len(ss) > 1 {
			param.DefaultValue = ss[1]
			if len(ss) > 2 {
				if ss[2] == "out" {
					outs = append(outs, param)
					param.DefaultValue = ""
				}
			} else {
				ins = append(ins, param)
			}
		} else {
			ins = append(ins, param)
		}
	}
	md := new(nodeconv.Module)
	md.Name = name
	md.Sysmbol = sysmbol
	md.Desc = desc
	md.ModelID = strconv.Itoa(o.GetModelID())
	md.ModelName = GetModName(o.GetModelID())
	data, _ := json.Marshal(ins)
	md.In = string(data)

	data, _ = json.Marshal(outs)
	md.Out = string(data)

	data, _ = json.Marshal(md)
	l := len(data)
	data[l-1] = ','
	data = append(data, []byte(`"languageType":"go"}`)...)
	return data
}
